package service.genetic;

import materials.matrix.MatrixMaterialInterface;
import materials.network.NetworkInterface;

/**
 * A Service to Use Genetic Algorithm Features on NeuronalNetworks
 * @author User
 *
 */
public class NetworkGeneticService {

	public NetworkInterface recombineNetworks(NetworkInterface n1, NetworkInterface n2){
		NetworkInterface result = n1.clone();
		int temp = n1.getLayerNumber();
		for(int i = 1; i < temp;i++){
			MatrixMaterialInterface temp_n1 = n1.getWeigthMatrix(i);
			MatrixMaterialInterface temp_n2 = n2.getWeigthMatrix(i);
			MatrixMaterialInterface temp_result = result.getWeigthMatrix(i);
			for(int m = 1; m < temp_n1.getM(); m++){
				for(int n = 1; n < temp_n1.getN(); n++){
					if(Math.random() > 0.5){
						temp_result.setValue(m, n, temp_n1.getValue(m, n));
					}else{
						temp_result.setValue(m, n, temp_n2.getValue(m, n));
					}
				}			
			}
		}
		return result;
	}
	
	
	public NetworkInterface recombineNetworksAverage(NetworkInterface n1, NetworkInterface n2){
		NetworkInterface result = n1.clone();
		for(int i = 1; i < n1.getLayerNumber();i++){
			MatrixMaterialInterface temp_n1 = n1.getWeigthMatrix(i);
			MatrixMaterialInterface temp_n2 = n2.getWeigthMatrix(i);
			MatrixMaterialInterface temp_result = result.getWeigthMatrix(i);
			for(int m = 1; m < temp_n1.getM(); m++){
				for(int n = 1; n < temp_n1.getN(); n++){
					double t = 	 temp_n1.getValue(m, n) + temp_n2.getValue(m, n);
					temp_result.setValue(m, n,t/2);				
				}			
			}
		}
		return result;
	}
	
	
	
	public NetworkInterface mutateNetwork(NetworkInterface netz, double percent, double d){
		assert netz != null : "Vorbedingung verletzt: n != null";
		assert percent > 0 : "Vorbedingung verletzt: percent";
		for(int i = 1; i < netz.getLayerNumber();i++){
			for(int m = 0; m < netz.getWeigthMatrix(i).getM();m++){
				for(int n = 0; n < netz.getWeigthMatrix(i).getN();n++){
					if(Math.random() < percent){
						netz.getWeigthMatrix(i).setValue(m+1, n+1, netz.getWeigthMatrix(i).getValue(m+1, n+1)+(Math.random()-0.5) *d);
					}
				}
			}
		}
		return netz;
	}
	
	public NetworkInterface CrossOverNetwork(NetworkInterface netz, double percent,int times){
		
		for(int i = 0; i < times; i++){
			if(Math.random() < percent){
				int layer = (int) (Math.random() * (netz.getLayerNumber()-1));
				MatrixMaterialInterface mi = netz.getWeigthMatrix(layer+1);
				int m1 = (int) ((Math.random() * mi.getM()) +1);
				int m2 = (int) ((Math.random() * mi.getM()) +1);
				int n1 = (int) ((Math.random() * mi.getN()) +1);
				int n2 = (int) ((Math.random() * mi.getN()) +1);	
				
				
				double val1 = mi.getValue(m1, n1);
				double val2 = mi.getValue(m2, n2);
				
				mi.setValue(m1, n1, val2);
				mi.setValue(m2, n2, val1);
			}
		}
		return netz;
	}
	
	public NetworkInterface mutateNetworkRandom(NetworkInterface netz, double percent, double d){
		assert netz != null : "Vorbedingung verletzt: n != null";
		assert percent > 0 : "Vorbedingung verletzt: percent";
		for(int i = 1; i < netz.getLayerNumber();i++){
			for(int m = 0; m < netz.getWeigthMatrix(i).getM();m++){
				for(int n = 0; n < netz.getWeigthMatrix(i).getN();n++){
					if(Math.random() < percent){
						netz.getWeigthMatrix(i).setValue(m+1, n+1,(Math.random()-0.5) *d);
					}
				}
			}
		}
		return netz;
	}
	
	
}
